home *** CD-ROM | disk | FTP | other *** search
/ Freelog 125 / Freelog_MarsAvril2015_No125.iso / Musique / Quod Libet / quodlibet-3.3.0-installer.exe / bin / quodlibet / ext / events / mediaserver.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2014-12-31  |  26KB  |  613 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.7)
  3.  
  4. import os
  5. import sys
  6. if os.name == 'nt' or sys.platform == 'darwin':
  7.     from quodlibet.plugins import PluginNotSupportedError
  8.     raise PluginNotSupportedError
  9. import tempfile
  10. from gi.repository import Gtk, GdkPixbuf
  11. import dbus
  12. import dbus.service as dbus
  13. from quodlibet import app
  14. from quodlibet.plugins.events import EventPlugin
  15. from quodlibet.parse import Pattern
  16. from quodlibet.util.uri import URI
  17. from quodlibet.util.dbusutils import DBusIntrospectable, DBusProperty
  18. from quodlibet.util.dbusutils import dbus_unicode_validate as unival
  19. BASE_PATH = '/org/gnome/UPnP/MediaServer2'
  20. BUS_NAME = 'org.gnome.UPnP.MediaServer2.QuodLibet'
  21.  
  22. class MediaServer(EventPlugin):
  23.     PLUGIN_ID = 'mediaserver'
  24.     PLUGIN_NAME = _('UPnP AV Media Server')
  25.     PLUGIN_DESC = _('Exposes all albums to the Rygel UPnP Media Server through the MediaServer2 D-Bus interface')
  26.     PLUGIN_ICON = Gtk.STOCK_CONNECT
  27.     PLUGIN_VERSION = '0.1'
  28.     
  29.     def enabled(self):
  30.         
  31.         try:
  32.             dbus.SessionBus()
  33.         except dbus.DBusException:
  34.             self.objects = []
  35.             return None
  36.  
  37.         entry = EntryObject()
  38.         albums = AlbumsObject(entry, app.library)
  39.         song = SongObject(app.library, [
  40.             albums])
  41.         icon = Icon(entry)
  42.         self.objects = [
  43.             entry,
  44.             albums,
  45.             song,
  46.             icon]
  47.  
  48.     
  49.     def disabled(self):
  50.         for obj in self.objects:
  51.             obj.remove_from_connection()
  52.         
  53.         for obj in self.objects:
  54.             obj.destroy()
  55.         
  56.         del self.objects
  57.         import gc as gc
  58.         gc.collect()
  59.  
  60.  
  61.  
  62. class DBusPropertyFilter(DBusProperty):
  63.     '''Adds some methods to support the MediaContainer property filtering.'''
  64.     
  65.     def get_properties_for_filter(self, interface, filter_):
  66.         props = self.get_properties(interface)
  67.         if '*' not in filter_:
  68.             props = [ p for p in props if p[1] in filter_ ]
  69.         return props
  70.  
  71.     
  72.     def get_values(self, properties, path = '/'):
  73.         result = { }
  74.         for iface, prop in properties:
  75.             result[prop] = self.get_value(iface, prop, path)
  76.         
  77.         return result
  78.  
  79.  
  80.  
  81. class MediaContainer(object):
  82.     IFACE = 'org.gnome.UPnP.MediaContainer2'
  83.     ISPEC_PROP = '\n<property type="u" name="ChildCount" access="read"/>\n<property type="u" name="ItemCount" access="read"/>\n<property type="u" name="ContainerCount" access="read"/>\n<property type="b" name="Searchable" access="read"/>\n<property type="o" name="Icon" access="read"/>\n'
  84.     ISPEC = '\n<method name="ListChildren">\n    <arg type="u" name="offset" direction="in"/>\n    <arg type="u" name="max" direction="in"/>\n    <arg type="as" name="filter" direction="in"/>\n    <arg type="aa{sv}" name="arg_3" direction="out"/>\n</method>\n<method name="ListContainers">\n    <arg type="u" name="offset" direction="in"/>\n    <arg type="u" name="max" direction="in"/>\n    <arg type="as" name="filter" direction="in"/>\n    <arg type="aa{sv}" name="arg_3" direction="out"/>\n</method>\n<method name="ListItems">\n    <arg type="u" name="offset" direction="in"/>\n    <arg type="u" name="max" direction="in"/>\n    <arg type="as" name="filter" direction="in"/>\n    <arg type="aa{sv}" name="arg_3" direction="out"/>\n</method>\n<method name="SearchObjects">\n    <arg type="s" name="query" direction="in"/>\n    <arg type="u" name="offset" direction="in"/>\n    <arg type="u" name="max" direction="in"/>\n    <arg type="as" name="filter" direction="in"/>\n    <arg type="aa{sv}" name="arg_4" direction="out"/>\n</method>\n\n<signal name="Updated"/>\n'
  85.     
  86.     def __init__(self, optional = tuple()):
  87.         self.set_introspection(MediaContainer.IFACE, MediaContainer.ISPEC)
  88.         props = [
  89.             'ChildCount',
  90.             'ItemCount',
  91.             'ContainerCount',
  92.             'Searchable']
  93.         props += list(optional)
  94.         self.set_properties(MediaContainer.IFACE, MediaContainer.ISPEC_PROP, wl = props)
  95.         self.implement_interface(MediaContainer.IFACE, MediaObject.IFACE)
  96.  
  97.     
  98.     def emit_updated(self, path = '/'):
  99.         self.Updated(rel = path)
  100.  
  101.     
  102.     def ListChildren(self, offset, max_, filter_, path):
  103.         if self.SUPPORTS_MULTIPLE_OBJECT_PATHS:
  104.             return self.list_children(offset, max_, filter_, path)
  105.         return None.list_children(offset, max_, filter_)
  106.  
  107.     ListChildren = dbus.service.method(IFACE, in_signature = 'uuas', out_signature = 'aa{sv}', rel_path_keyword = 'path')(ListChildren)
  108.     
  109.     def ListContainers(self, offset, max_, filter_, path):
  110.         if self.SUPPORTS_MULTIPLE_OBJECT_PATHS:
  111.             return self.list_containers(offset, max_, filter_, path)
  112.         return None.list_containers(offset, max_, filter_)
  113.  
  114.     ListContainers = dbus.service.method(IFACE, in_signature = 'uuas', out_signature = 'aa{sv}', rel_path_keyword = 'path')(ListContainers)
  115.     
  116.     def ListItems(self, offset, max_, filter_, path):
  117.         if self.SUPPORTS_MULTIPLE_OBJECT_PATHS:
  118.             return self.list_items(offset, max_, filter_, path)
  119.         return None.list_items(offset, max_, filter_)
  120.  
  121.     ListItems = dbus.service.method(IFACE, in_signature = 'uuas', out_signature = 'aa{sv}', rel_path_keyword = 'path')(ListItems)
  122.     
  123.     def SearchObjects(self, query, offset, max_, filter_, path):
  124.         return []
  125.  
  126.     SearchObjects = dbus.service.method(IFACE, in_signature = 'suuas', out_signature = 'aa{sv}', rel_path_keyword = 'path')(SearchObjects)
  127.     
  128.     def Updated(self, rel = ''):
  129.         pass
  130.  
  131.     Updated = dbus.service.signal(IFACE, rel_path_keyword = 'rel')(Updated)
  132.  
  133.  
  134. class MediaObject(object):
  135.     IFACE = 'org.gnome.UPnP.MediaObject2'
  136.     ISPEC = '\n<property type="o" name="Parent" access="read"/>\n<property type="s" name="Type" access="read"/>\n<property type="o" name="Path" access="read"/>\n<property type="s" name="DisplayName" access="read"/>\n'
  137.     parent = None
  138.     
  139.     def __init__(self, parent = None):
  140.         self.set_properties(MediaObject.IFACE, MediaObject.ISPEC)
  141.         if not parent:
  142.             pass
  143.         self.parent = self
  144.  
  145.  
  146.  
  147. class MediaItem(object):
  148.     IFACE = 'org.gnome.UPnP.MediaItem2'
  149.     ISPEC = '\n<property type="as" name="URLs" access="read"/>\n<property type="s" name="MIMEType" access="read"/>\n\n<property type="x" name="Size" access="read"/>\n<property type="s" name="Artist" access="read"/>\n<property type="s" name="Album" access="read"/>\n<property type="s" name="Date" access="read"/>\n<property type="s" name="Genre" access="read"/>\n<property type="s" name="DLNAProfile" access="read"/>\n\n<property type="i" name="Duration" access="read"/>\n<property type="i" name="Bitrate" access="read"/>\n<property type="i" name="SampleRate" access="read"/>\n<property type="i" name="BitsPerSample" access="read"/>\n\n<property type="i" name="Width" access="read"/>\n<property type="i" name="Height" access="read"/>\n<property type="i" name="ColorDepth" access="read"/>\n<property type="i" name="PixelWidth" access="read"/>\n<property type="i" name="PixelHeight" access="read"/>\n<property type="o" name="Thumbnail" access="read"/>\n\n<property type="o" name="AlbumArt" access="read"/>\n\n<property type="i" name="TrackNumber" access="read"/>\n'
  150.     
  151.     def __init__(self, optional = tuple()):
  152.         props = [
  153.             'URLs',
  154.             'MIMEType'] + list(optional)
  155.         self.set_properties(MediaItem.IFACE, MediaItem.ISPEC, wl = props)
  156.         self.implement_interface(MediaItem.IFACE, MediaObject.IFACE)
  157.  
  158.  
  159.  
  160. class EntryObject(MediaContainer, MediaObject, DBusPropertyFilter, DBusIntrospectable, dbus.service.Object):
  161.     PATH = BASE_PATH + '/QuodLibet'
  162.     DISPLAY_NAME = "@REALNAME@'s Quod Libet on @HOSTNAME@"
  163.     
  164.     def __init__(self):
  165.         self._EntryObject__sub = []
  166.         DBusIntrospectable.__init__(self)
  167.         DBusPropertyFilter.__init__(self)
  168.         MediaObject.__init__(self)
  169.         MediaContainer.__init__(self, optional = [
  170.             'Icon'])
  171.         bus = dbus.SessionBus()
  172.         name = dbus.service.BusName(BUS_NAME, bus)
  173.         dbus.service.Object.__init__(self, bus, self.PATH, name)
  174.  
  175.     
  176.     def get_property(self, interface, name):
  177.         if interface == MediaContainer.IFACE:
  178.             if name == 'ChildCount':
  179.                 return len(self._EntryObject__sub)
  180.             if None == 'ItemCount':
  181.                 return 0
  182.             if None == 'ContainerCount':
  183.                 return len(self._EntryObject__sub)
  184.             if None == 'Searchable':
  185.                 return False
  186.             if None == 'Icon':
  187.                 return Icon.PATH
  188.         if interface == MediaObject.IFACE:
  189.             if name == 'Parent':
  190.                 return self.parent.PATH
  191.             if None == 'Type':
  192.                 return 'container'
  193.             if None == 'Path':
  194.                 return self.PATH
  195.             if None == 'DisplayName':
  196.                 return self.DISPLAY_NAME
  197.  
  198.     
  199.     def destroy(self):
  200.         del self._EntryObject__sub
  201.         del self.parent
  202.  
  203.     
  204.     def register_child(self, child):
  205.         self._EntryObject__sub.append(child)
  206.         self.emit_properties_changed(MediaContainer.IFACE, [
  207.             'ChildCount',
  208.             'ContainerCount'])
  209.  
  210.     
  211.     def list_containers(self, offset, max_, filter_):
  212.         props = self.get_properties_for_filter(MediaContainer.IFACE, filter_)
  213.         if not max_ or offset + max_:
  214.             pass
  215.         end = None
  216.         result = []
  217.         for sub in self._EntryObject__sub[offset:end]:
  218.             result.append(sub.get_values(props))
  219.         
  220.         return result
  221.  
  222.     list_children = list_containers
  223.     
  224.     def list_items(self, offset, max_, filter_):
  225.         return []
  226.  
  227.  
  228. SUPPORTED_SONG_PROPERTIES = ('Size', 'Artist', 'Album', 'Date', 'Genre', 'Duration', 'TrackNumber')
  229.  
  230. class DummySongObject(MediaItem, MediaObject, DBusPropertyFilter, DBusIntrospectable):
  231.     ''' A dummy song object that is not exported on the bus, but supports
  232.     the usual interfaces.
  233.  
  234.     You need to assign a real song before using it, and have to pass
  235.     a path prefix.
  236.  
  237.     The path of the song is /org/gnome/UPnP/MediaServer2/Song/<PREFIX>/SongID
  238.     This lets us reconstruct the original parent path:
  239.     /org/gnome/UPnP/MediaServer2/<PREFIX>
  240.  
  241.     atm. a prefix can look like "Albums/123456"
  242.     '''
  243.     SUPPORTS_MULTIPLE_OBJECT_PATHS = False
  244.     __pattern = Pattern('<discnumber|<discnumber>.><tracknumber>. <title>')
  245.     
  246.     def __init__(self, parent):
  247.         DBusIntrospectable.__init__(self)
  248.         DBusPropertyFilter.__init__(self)
  249.         MediaObject.__init__(self, parent)
  250.         MediaItem.__init__(self, optional = SUPPORTED_SONG_PROPERTIES)
  251.  
  252.     
  253.     def set_song(self, song, prefix):
  254.         self._DummySongObject__song = song
  255.         self._DummySongObject__prefix = prefix
  256.  
  257.     
  258.     def get_property(self, interface, name):
  259.         if interface == MediaObject.IFACE:
  260.             if name == 'Parent':
  261.                 return BASE_PATH + '/' + self._DummySongObject__prefix
  262.             if None == 'Type':
  263.                 return 'music'
  264.             if None == 'Path':
  265.                 path = SongObject.PATH
  266.                 path += '/' + self._DummySongObject__prefix + '/' + str(id(self._DummySongObject__song))
  267.                 return path
  268.             if None == 'DisplayName':
  269.                 return unival(self._DummySongObject__song.comma('title'))
  270.         if interface == MediaItem.IFACE:
  271.             if name == 'URLs':
  272.                 return [
  273.                     self._DummySongObject__song('~uri')]
  274.             if None == 'MIMEType':
  275.                 mimes = self._DummySongObject__song.mimes
  276.                 if mimes:
  277.                     pass
  278.                 return mimes[0]
  279.             if None == 'Size':
  280.                 return self._DummySongObject__song('~#filesize')
  281.             if None == 'Artist':
  282.                 return unival(self._DummySongObject__song.comma('artist'))
  283.             if None == 'Album':
  284.                 return unival(self._DummySongObject__song.comma('album'))
  285.             if None == 'Date':
  286.                 return unival(self._DummySongObject__song.comma('date'))
  287.             if None == 'Genre':
  288.                 return unival(self._DummySongObject__song.comma('genre'))
  289.             if None == 'Duration':
  290.                 return self._DummySongObject__song('~#length')
  291.             if None == 'TrackNumber':
  292.                 return self._DummySongObject__song('~#track', 0)
  293.  
  294.  
  295.  
  296. class DummyAlbumObject(MediaContainer, MediaObject, DBusPropertyFilter, DBusIntrospectable):
  297.     SUPPORTS_MULTIPLE_OBJECT_PATHS = False
  298.     __pattern = Pattern('<albumartist|<~albumartist~album>|<~artist~album>>')
  299.     
  300.     def __init__(self, parent):
  301.         DBusIntrospectable.__init__(self)
  302.         DBusPropertyFilter.__init__(self)
  303.         MediaObject.__init__(self, parent)
  304.         MediaContainer.__init__(self)
  305.         self._DummyAlbumObject__song = DummySongObject(self)
  306.  
  307.     
  308.     def get_dummy(self, song):
  309.         self._DummyAlbumObject__song.set_song(song, 'Albums/' + str(id(self._DummyAlbumObject__album)))
  310.         return self._DummyAlbumObject__song
  311.  
  312.     
  313.     def set_album(self, album):
  314.         self._DummyAlbumObject__album = album
  315.         self.PATH = self.parent.PATH + '/' + str(id(album))
  316.  
  317.     
  318.     def get_property(self, interface, name):
  319.         if interface == MediaContainer.IFACE:
  320.             if name == 'ChildCount' or name == 'ItemCount':
  321.                 return len(self._DummyAlbumObject__album.songs)
  322.             if None == 'ContainerCount':
  323.                 return 0
  324.             if None == 'Searchable':
  325.                 return False
  326.         if interface == MediaObject.IFACE:
  327.             if name == 'Parent':
  328.                 return self.parent.PATH
  329.             if None == 'Type':
  330.                 return 'container'
  331.             if None == 'Path':
  332.                 return self.PATH
  333.             if None == 'DisplayName':
  334.                 return unival(self._DummyAlbumObject__pattern % self._DummyAlbumObject__album)
  335.  
  336.     
  337.     def list_containers(self, offset, max_, filter_):
  338.         return []
  339.  
  340.     
  341.     def list_items(self, offset, max_, filter_):
  342.         songs = sorted(self._DummyAlbumObject__album.songs, key = (lambda s: s.sort_key))
  343.         dummy = self.get_dummy(None)
  344.         props = dummy.get_properties_for_filter(MediaItem.IFACE, filter_)
  345.         if not max_ or offset + max_:
  346.             pass
  347.         end = None
  348.         result = []
  349.         for song in songs[offset:end]:
  350.             result.append(self.get_dummy(song).get_values(props))
  351.         
  352.         return result
  353.  
  354.     list_children = list_items
  355.  
  356.  
  357. class SongObject(MediaItem, MediaObject, DBusProperty, DBusIntrospectable, dbus.service.FallbackObject):
  358.     PATH = BASE_PATH + '/Song'
  359.     
  360.     def __init__(self, library, users):
  361.         DBusIntrospectable.__init__(self)
  362.         DBusProperty.__init__(self)
  363.         MediaObject.__init__(self, None)
  364.         MediaItem.__init__(self, optional = SUPPORTED_SONG_PROPERTIES)
  365.         bus = dbus.SessionBus()
  366.         self.ref = dbus.service.BusName(BUS_NAME, bus)
  367.         dbus.service.FallbackObject.__init__(self, bus, self.PATH)
  368.         self._SongObject__library = library
  369.         self._SongObject__map = dict((lambda .0: pass)(self._SongObject__library.itervalues()))
  370.         self._SongObject__reverse = dict((lambda .0: pass)(self._SongObject__map.iteritems()))
  371.         self._SongObject__song = DummySongObject(self)
  372.         self._SongObject__users = users
  373.         signals = [
  374.             ('changed', self._SongObject__songs_changed),
  375.             ('removed', self._SongObject__songs_removed),
  376.             ('added', self._SongObject__songs_added)]
  377.         self._SongObject__sigs = (map,)((lambda .0: (s, f) = .0self._SongObject__library.connect(s, f)), signals)
  378.  
  379.     
  380.     def __songs_changed(self, lib, songs):
  381.         props = [ p[1] for p in self.get_properties(MediaItem.IFACE) ]
  382.         for song in songs:
  383.             song_id = str(id(song))
  384.             if song_id not in self._SongObject__map:
  385.                 continue
  386.             for user in self._SongObject__users:
  387.                 prefix = user.get_prefix(song)
  388.                 path = '/' + prefix + '/' + song_id
  389.                 self.emit_properties_changed(MediaItem.IFACE, props, path)
  390.             
  391.         
  392.  
  393.     
  394.     def __songs_added(self, lib, songs):
  395.         for song in songs:
  396.             new_id = id(song)
  397.             self._SongObject__map[new_id] = song
  398.             self._SongObject__reverse[song] = new_id
  399.         
  400.  
  401.     
  402.     def __songs_removed(self, lib, songs):
  403.         for song in songs:
  404.             del self._SongObject__map[self._SongObject__reverse[song]]
  405.             del self._SongObject__reverse[song]
  406.         
  407.  
  408.     
  409.     def destroy(self):
  410.         for signal_id in self._SongObject__sigs:
  411.             self._SongObject__library.disconnect(signal_id)
  412.         
  413.  
  414.     
  415.     def get_dummy(self, song, prefix):
  416.         self._SongObject__song.set_song(song, prefix)
  417.         return self._SongObject__song
  418.  
  419.     
  420.     def get_property(self, interface, name, path):
  421.         (prefix, song_id) = path[1:].rsplit('/', 1)
  422.         song = self._SongObject__map[int(song_id)]
  423.         return self.get_dummy(song, prefix).get_property(interface, name)
  424.  
  425.  
  426.  
  427. class AlbumsObject(MediaContainer, MediaObject, DBusPropertyFilter, DBusIntrospectable, dbus.service.FallbackObject):
  428.     PATH = BASE_PATH + '/Albums'
  429.     DISPLAY_NAME = 'Albums'
  430.     
  431.     def __init__(self, parent, library):
  432.         DBusIntrospectable.__init__(self)
  433.         DBusPropertyFilter.__init__(self)
  434.         MediaObject.__init__(self, parent)
  435.         MediaContainer.__init__(self)
  436.         bus = dbus.SessionBus()
  437.         self.ref = dbus.service.BusName(BUS_NAME, bus)
  438.         dbus.service.FallbackObject.__init__(self, bus, self.PATH)
  439.         parent.register_child(self)
  440.         self._AlbumsObject__library = library.albums
  441.         self._AlbumsObject__library.load()
  442.         self._AlbumsObject__map = dict((lambda .0: pass)(self._AlbumsObject__library.itervalues()))
  443.         self._AlbumsObject__reverse = dict((lambda .0: pass)(self._AlbumsObject__map.iteritems()))
  444.         signals = [
  445.             ('changed', self._AlbumsObject__albums_changed),
  446.             ('removed', self._AlbumsObject__albums_removed),
  447.             ('added', self._AlbumsObject__albums_added)]
  448.         self._AlbumsObject__sigs = (map,)((lambda .0: (s, f) = .0self._AlbumsObject__library.connect(s, f)), signals)
  449.         self._AlbumsObject__dummy = DummyAlbumObject(self)
  450.  
  451.     
  452.     def get_dummy(self, album):
  453.         self._AlbumsObject__dummy.set_album(album)
  454.         return self._AlbumsObject__dummy
  455.  
  456.     
  457.     def get_path_dummy(self, path):
  458.         return self.get_dummy(self._AlbumsObject__map[int(path[1:])])
  459.  
  460.     
  461.     def __albums_changed(self, lib, albums):
  462.         for album in albums:
  463.             rel_path = '/' + str(id(album))
  464.             self.emit_updated(rel_path)
  465.             self.emit_properties_changed(MediaContainer.IFACE, [
  466.                 'ChildCount',
  467.                 'ItemCount',
  468.                 'DisplayName'], rel_path)
  469.         
  470.  
  471.     
  472.     def __albums_added(self, lib, albums):
  473.         for album in albums:
  474.             new_id = id(album)
  475.             self._AlbumsObject__map[new_id] = album
  476.             self._AlbumsObject__reverse[album] = new_id
  477.         
  478.         self.emit_updated()
  479.         self.emit_properties_changed(MediaContainer.IFACE, [
  480.             'ChildCount',
  481.             'ContainerCount'])
  482.  
  483.     
  484.     def __albums_removed(self, lib, albums):
  485.         for album in albums:
  486.             del self._AlbumsObject__map[self._AlbumsObject__reverse[album]]
  487.             del self._AlbumsObject__reverse[album]
  488.         
  489.         self.emit_updated()
  490.         self.emit_properties_changed(MediaContainer.IFACE, [
  491.             'ChildCount',
  492.             'ContainerCount'])
  493.  
  494.     
  495.     def get_prefix(self, song):
  496.         album = self._AlbumsObject__library[song.album_key]
  497.         return 'Albums/' + str(id(album))
  498.  
  499.     
  500.     def destroy(self):
  501.         for signal_id in self._AlbumsObject__sigs:
  502.             self._AlbumsObject__library.disconnect(signal_id)
  503.         
  504.  
  505.     
  506.     def __get_albums_property(self, interface, name):
  507.         if interface == MediaContainer.IFACE:
  508.             if name == 'ChildCount':
  509.                 return len(self._AlbumsObject__library)
  510.             if None == 'ItemCount':
  511.                 return 0
  512.             if None == 'ContainerCount':
  513.                 return len(self._AlbumsObject__library)
  514.             if None == 'Searchable':
  515.                 return False
  516.         if interface == MediaObject.IFACE:
  517.             if name == 'Parent':
  518.                 return self.parent.PATH
  519.             if None == 'Type':
  520.                 return 'container'
  521.             if None == 'Path':
  522.                 return self.PATH
  523.             if None == 'DisplayName':
  524.                 return self.DISPLAY_NAME
  525.  
  526.     
  527.     def get_property(self, interface, name, path):
  528.         if path == '/':
  529.             return self._AlbumsObject__get_albums_property(interface, name)
  530.         return None.get_path_dummy(path).get_property(interface, name)
  531.  
  532.     
  533.     def __list_albums(self, offset, max_, filter_):
  534.         props = self.get_properties_for_filter(MediaContainer.IFACE, filter_)
  535.         albums = sorted(self._AlbumsObject__library, key = (lambda a: a.sort))
  536.         if not max_ or offset + max_:
  537.             pass
  538.         end = None
  539.         result = []
  540.         for album in albums[offset:end]:
  541.             result.append(self.get_dummy(album).get_values(props))
  542.         
  543.         return result
  544.  
  545.     
  546.     def list_containers(self, offset, max_, filter_, path):
  547.         if path == '/':
  548.             return self._AlbumsObject__list_albums(offset, max_, filter_)
  549.  
  550.     
  551.     def list_items(self, offset, max_, filter_, path):
  552.         if path != '/':
  553.             return self.get_path_dummy(path).list_items(offset, max_, filter_)
  554.  
  555.     
  556.     def list_children(self, offset, max_, filter_, path):
  557.         if path == '/':
  558.             return self._AlbumsObject__list_albums(offset, max_, filter_)
  559.         return None.get_path_dummy(path).list_children(offset, max_, filter_)
  560.  
  561.  
  562.  
  563. class Icon(MediaItem, MediaObject, DBusProperty, DBusIntrospectable, dbus.service.Object):
  564.     PATH = BASE_PATH + '/Icon'
  565.     SIZE = 160
  566.     
  567.     def __init__(self, parent):
  568.         DBusIntrospectable.__init__(self)
  569.         DBusProperty.__init__(self)
  570.         MediaObject.__init__(self, parent = parent)
  571.         MediaItem.__init__(self, optional = [
  572.             'Height',
  573.             'Width',
  574.             'ColorDepth'])
  575.         bus = dbus.SessionBus()
  576.         name = dbus.service.BusName(BUS_NAME, bus)
  577.         dbus.service.Object.__init__(self, bus, self.PATH, name)
  578.         self.implement_interface('org.gnome.UPnP.MediaItem1', MediaItem.IFACE)
  579.         theme = Gtk.IconTheme.get_default()
  580.         pixbuf = theme.load_icon('quodlibet', Icon.SIZE, 0)
  581.         pixbuf = pixbuf.scale_simple(Icon.SIZE, Icon.SIZE, GdkPixbuf.InterpType.BILINEAR)
  582.         self._Icon__depth = pixbuf.get_bits_per_sample()
  583.         self._Icon__f = f = tempfile.NamedTemporaryFile()
  584.         pixbuf.savev(f.name, 'png', [], [])
  585.  
  586.     
  587.     def get_property(self, interface, name):
  588.         if interface == MediaObject.IFACE:
  589.             if name == 'Parent':
  590.                 return EntryObject.PATH
  591.             if None == 'Type':
  592.                 return 'image'
  593.             if None == 'Path':
  594.                 return Icon.PATH
  595.             if None == 'DisplayName':
  596.                 return "I'm an icon \\o/"
  597.         if interface == MediaItem.IFACE:
  598.             if name == 'URLs':
  599.                 return [
  600.                     URI.frompath(self._Icon__f.name)]
  601.             if None == 'MIMEType':
  602.                 return 'image/png'
  603.             if None == 'Width' or name == 'Height':
  604.                 return Icon.SIZE
  605.             if None == 'ColorDepth':
  606.                 return self._Icon__depth
  607.  
  608.     
  609.     def destroy(self):
  610.         pass
  611.  
  612.  
  613.